﻿using System;
using RrslLite.Configuration;
using RrslLite.Dsl;
using RrslLite.Net.Aop;
using RrslLite.Net.Messages;

namespace RrslLite.Net.BatchImpl
{
    public class AsyncBatchCallBuilder<TTarget> : BatchCallBuilder<TTarget> where TTarget : class
    {
        private readonly AsyncBatchBuilder _batchBuilder;

        protected BatchBuilderConfiguration BatchBuilderConfiguration
        {
            get { return RrslLiteConfiguration.Instance.BatchBuilderConfiguration; }
        }

        protected BatchCallBuilderConfiguration BatchCallBuilderConfiguration
        {
            get { return BatchBuilderConfiguration.BatchCallBuilderConfiguration; }
        }

        public AsyncBatchCallBuilder(AsyncBatchBuilder batchBuilder) : base(batchBuilder)
        {
            if(batchBuilder == null)
                throw new ArgumentNullException("batchBuilder");

            _batchBuilder = batchBuilder;
        }

        protected override BatchFuncCall<TResult> CreateBatchFuncCall<TResult>(Func<TTarget, TResult> call, Action<TResult> handler)
        {
            Action<BatchCall> wcfCall = c =>
                                            {
                                                var svc = CreateServiceProxyForCall(c.CorrelationId);
                                                call(svc);
                                            };
            return new BatchFuncCall<TResult>(wcfCall, handler);
        }

        protected override BatchVoidCall CreateBatchVoidCall(Action<TTarget> call, Action handler)
        {
            Action<BatchCall> wcfCall = c =>
                                            {
                                                var svc = CreateServiceProxyForCall(c.CorrelationId);
                                                call(svc);
                                            };
            return new BatchVoidCall(wcfCall, handler);
        }

        protected virtual TTarget CreateServiceProxyForCall(Guid callId)
        {
            Message msg = CreateMessage(callId);

            _batchBuilder.CurrentBatch.AddMessage(msg);

            using (var proxyGenerator = BatchBuilderConfiguration.EntityAopProxyGeneratorConfiguration.ProxyGeneratorCreateFunc())
            {
                var interceptor = new InterceptorAsync<TTarget>(msg);
                return proxyGenerator.CreateInterfaceProxyWithoutTarget<TTarget>(interceptor);
            }
        }

        protected virtual Message CreateMessage(Guid correlationId)
        {
            return BatchCallBuilderConfiguration.MessageCreatorFunc(correlationId);
        }
    }
}